package me.chan.netty.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import me.chan.netty.message.Message;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

@Slf4j
public class MessageCodec extends ByteToMessageCodec<Message> {

    private static final String MAGIC_NUMBER = "CXJR";

    /**
     *  Description:<br/>
     *  魔数，用来在第一时间判定是否是无效数据包<br/>
     *  版本号，可以支持协议的升级<br/>
     *  序列化算法，消息正文到底采用哪种序列化反序列化方式，可以由此扩展，例如：json、protobuf、hessian、jdk<br/>
     *  指令类型，是登录、注册、单聊、群聊... 跟业务相关<br/>
     *  请求序号，为了双工通信，提供异步能力<br/>
     *  正文长度<br/>
     *  消息正文<br/>
     * @param ctx
     * @param msg
     * @param out
     * @throws Exception
     */

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {

        // magic number  4B
        out.writeBytes(MAGIC_NUMBER.getBytes());
        // version   1B
        out.writeByte(0x01);
        // serialize algo 1B
        out.writeByte(0x00);
        // business related command 1B
        out.writeByte(msg.getMessageType());
        // sequenceId  4B
        out.writeInt(msg.getSequenceId());
        // nonsense  1B
        out.writeByte(0xff);
        // content length 4B
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] content = bos.toByteArray();
        out.writeInt(content.length);
        // content
        out.writeBytes(content);

    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magicNumber = in.readInt();
        int version = in.readByte();
        int serializeAlgo = in.readByte();
        int msgType = in.readByte();
        int sequenceId = in.readInt();
        in.readByte();
        int length = in.readInt();
        byte[] content = new byte[length];
        in.readBytes(content, 0, length);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(content));
        Message message = (Message) ois.readObject();
        log.debug("{}, {}, {}, {}, {}, {}",
                magicNumber, version, serializeAlgo, msgType, sequenceId, length);
        System.out.println();
        log.debug("{}", message);
        out.add(message);
    }
}
